<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
<script>
    //21-04-20 夜 整理 
//obj
        const obj = {
            a:1,
            b:2,
            c:3
        }
        for(let i of obj){
            console.log(i)          //报错 obj对象是不可迭代的     iterable可迭代的   
            console.log(obj.i)                                   //iterable可迭代的
        }
        for(let i in obj){
            console.log(i)           //a b c 遍历对象返回的对象的key值,
        }

//arr 
            const arr = ["a","b","c"]
            for(let i of arr){  
                console.log(i)           //a b c   for of循环 遍历的是可迭代对象所定义的要迭代的数据  es6用法 可终止循环 
            }
            
            for(let i in arr){  
                // if (arr.hasOwnProperty(i)){}  加条件排除原型添加的 
                console.log(arr[i])      //a b c   
                console.log(i)           //0 1 2   for-in循环 返回可枚举的属性 所以对于数组来说打印的是键 而不是值
            }                            
            //注意，从技术上来讲你可以使用for-in循环数组（因为JavaScript中数组也是对象），但这是不推荐的。因为如果数组对象已被自定义的功能增强，就可能发生逻辑错误。 

   //原型get 
    const arr =  ["1","2"]  
    arr.name = "w"
    for(let i in arr){
        console.log( i )         
    }                            //0 1 name  for-in循环 不仅可以遍历数字键名,还会遍历原型上的值 和手动添加的其他键


    //
    //遍历对象返回的对象的key值,  遍历数组返回的数组的下标(key)。
    //for in 循环同样在查找对象属性时遍历原型链上的所有属性。
    
    // Object.prototype.bar = 1;    
    // var foo = {moo: 2};
    // for(var i in foo) {
    //     console.log(i); // 输出两个属性：bar 和 moo
    // }

    // for in 循环 返回可枚举的属性
    // for of 循环 遍历的是可迭代对象所定义的要迭代的数据  es6用法 可终止循环 
    /*
         if(index === ‘ss’){
            //continue--break
        }
            //console.log(index)
        }//a cc
        */    

    //for-in +      
    /* for in应该用在非数组对象的遍历上, 使用for-in循环也被称为枚举 
    注意，从技术上来讲你可以使用for-in循环数组（因为JavaScript中数组也是对象），但这是不推荐的。因为如果数组对象已被自定义的功能增强，就可能发生逻辑错误。*/ 

    //hasOwnPrototype() 当你遍历对象属性的时候可以过滤掉从原型链上下来的属性，看代码示例  
    //思考下面的代码  
    var man = {       //字面量去创建一个对象 
        hands:2,
        legs:2,
        heads:1  
    };    
    Object.prototype.bar = 1;  //原型后添加  

    //这儿 在代码的某个地方 一个方法添加给了所有对象 
    //对象man定义完成后, 在对象的原型上增加一个名为clone的方法，这(原型链是时实的),以为这所有的对象可以访问新的方法
    //为了避免枚举man的时候出来clone()方法,则需要用hasOwnProperty()方法过滤原型属性。如果不做过滤，会导致clone()函数显示出来，在大多数情况下这是不希望出现的。
    if(typeof Object.prototype.clone === "undefined"){   
        Object.prototype.clone = function(){ };
    }
    for (var i in man) {
        if (man.hasOwnProperty(i)) { // 过滤
            console.log(i, ":", man[i]);    //hands:2, legs:2, heads:1 
        }
    }
    //反面例子 
    for (var i in man) {
        console.log(i, ":", man[i]);        //hands:2, legs:2, heads:1 bar：1，  clone(){} 
    }


    //注意通过判断一个属性是否undifined 是不够的 因为一个属性确实存在 只不过它的值被设置为undefined 
    //判断某个对象自身是否拥有某一属性 特点不会去原型上查看 
    //判断一个对象是否包含自定义属性 而不是原型上的属性 则需要使用继承自Object.prototype的hasOwnProperty
    //当检查对象上某个属性是否存在时，hasOwnProperty 是唯一可用的方法。 同时在使用 for in loop 遍历对象时，推荐总是使用 hasOwnProperty 方法， 这将会避免原型对象扩展带来的干扰
    //hasOwnProperty 是js唯一一个处理属性但不查找原型链的函数  代码如下
    Object.prototype.bar = 1; 
    var foo = {goo:undefined}

    console.log(foo.bar)         //1 
    console.log("bar" in foo)    //true 

    //hasOwnProperty 作为属性
    var foo = {
        hasOwnProperty: function() {
            return false;
        },
        bar: 'Here be dragons'
    };
    foo.hasOwnProperty('bar'); // 总是返回 false




</script>




